/* View a .fon font file */

#include "global.h"
#include "font.h"				/* font resource file ids */

#define HORZ_SPACING		8

/* .fon File data */
typedef struct {
	UINT				disp_lines ;				/* Lines on screen display */
	UINT				chars_per_line ;			/* Characters per line */
	UINT				width ;						/* Horizontal distance between successive chars */
	UINT				height ;						/* Vertical distance between successive chars */
	UINT				curr_x ;						/* Current x pos of cursor */
	UINT				curr_y ;						/* Current y pos of cursor */
	UINT				curr_line ;					/* Current top line */
	UINT				last_top_line ;			/* Last top line */
	UINT				num_lines ;					/* num of lines total to be displayed */
	BOOL				redraw ;						/* redraw flag */
	UINT				fontid ;						/* font id */
	G_FONT_INFO		fontinfo ;					/* font info */
} FON_DATA ;

LOCAL_D FON_DATA *		pdata = NULL ;

LOCAL_D H_MENU_DATA		Fontmdata[] = {	"File", 2,
														NULL } ;

LOCAL_D TEXT *				Fontcmds[] = {	"oOpen",
													"xExit",
													NULL } ;

LOCAL_C VOID InvertChar(INT x, INT y) {
	P_RECT		rect ;

	rect.tl.x = pdata->width * x ;
	rect.tl.y = pdata->height * y ;
	rect.br.x = rect.tl.x + pdata->fontinfo.max_width ;
	rect.br.y = rect.tl.y + pdata->height ;

	gCreateTempGC0(GetMainWid()) ;
	gClrRect(&rect, G_TRMODE_INV) ;
	gFreeTempGC() ;
}

LOCAL_C VOID DrawChar(INT ch, INT x, INT y) {
	P_RECT		rect ;
	G_GC			gc ;

	rect.tl.x = pdata->width * x ;
	rect.tl.y = pdata->height * y ;
	rect.br.x = rect.tl.x + pdata->width ;
	rect.br.y = rect.tl.y + pdata->height ;
	gc.font = pdata->fontid ;

	gCreateTempGC(GetMainWid(), G_GC_MASK_FONT, &gc) ;

	if (	ch >= pdata->fontinfo.low_ch &&
			ch <= pdata->fontinfo.high_ch )
		gPrintBoxText(	&rect,
							pdata->fontinfo.height,
							G_TEXT_ALIGN_LEFT,
							0,
							(TEXT *) &ch,
							1 ) ;
	else
		gClrRect(&rect, G_TRMODE_CLR) ;

	gFreeTempGC() ;
}

#pragma save, ENTER_CALL

LOCAL_C INT FontCleanUp(VOID) {
	if ( pdata != NULL ) {
		wFree(pdata->fontid) ;
		p_free(pdata) ;
		pdata = NULL ;
	}

	return(E_APP_NONE) ;
}

LOCAL_C INT FontInit(VOID) {
	pdata = f_alloc(sizeof(FON_DATA)) ;

	pdata->fontid = gOpenFont(file.name) ;
	
	gFontInfo(pdata->fontid, G_STY_NORMAL, &pdata->fontinfo) ;

	pdata->height = pdata->fontinfo.height + TEXT_LEADING ;
	pdata->width = pdata->fontinfo.max_width + HORZ_SPACING ;
	pdata->disp_lines = metrics.disp_size.y / pdata->height ;
	pdata->chars_per_line = MIN( metrics.disp_size.x / pdata->width, 16 ) ;

	if ( pdata->chars_per_line % 2 )
		pdata->chars_per_line-- ;

	pdata->redraw = TRUE ;
	pdata->curr_line = 0 ;
	pdata->curr_x = 0 ;
	pdata->curr_y = 0 ;

	pdata->num_lines = (pdata->fontinfo.high_ch - pdata->fontinfo.low_ch + 1) / pdata->chars_per_line ;
	if ( (pdata->fontinfo.high_ch - pdata->fontinfo.low_ch + 1) % pdata->chars_per_line )
		pdata->num_lines++ ;

	if ( pdata->num_lines <= pdata->disp_lines )
		pdata->last_top_line = 0 ;
	else
		pdata->last_top_line = pdata->num_lines - pdata->disp_lines ;

	SetMainWindowExtent(	0,
								0,
								pdata->chars_per_line * pdata->width,
								pdata->disp_lines * pdata->height ) ;

	return(E_APP_NONE) ;
}

LOCAL_C INT FontFileInfo(VOID) {
	TEXT				str[80] ;
	TEXT *			res_str = NULL ;
	H_DI_TEXT		dialog_txt = { NULL, H_DTEXT_ALIGN_LEFT } ;

	/* Display special info for FON files:
		Fast/Normal Font
		Char Range: xx-xx
		Height: xx pixels
	*/

	dialog_txt.str = str ;

	p_scpy(	dialog_txt.str,
				ReadResource(pdata->fontinfo.flags & G_FONT_SPECIAL_1 ? RS_FONT_FAST : RS_FONT_NORM, &res_str) ) ;
	p_free(res_str) ;
	res_str = NULL ;
	ZTStoBCS(dialog_txt.str) ;
	f_leave( uAddDialogItem(H_DIALOG_TEXT, NULL, &dialog_txt) ) ;

	p_atos(	dialog_txt.str,
				ReadResource(RS_FONT_RANGE, &res_str),
				pdata->fontinfo.low_ch,
				pdata->fontinfo.high_ch ) ;
	p_free(res_str) ;
	res_str = NULL ;

	ZTStoBCS(dialog_txt.str) ;
	f_leave( uAddDialogItem(H_DIALOG_TEXT, NULL, &dialog_txt) ) ;

	p_atos(	dialog_txt.str,
				ReadResource(RS_FONT_HEIGHT, &res_str),
				pdata->fontinfo.height ) ;
	p_free(res_str) ;
	res_str = NULL ;

	ZTStoBCS(dialog_txt.str) ;
	f_leave( uAddDialogItem(H_DIALOG_TEXT, NULL, &dialog_txt) ) ;

	return(E_APP_NONE) ;
}

LOCAL_C INT FontMenuExec(INT index) {
	switch ( index ) {
		case 0 :
			MainDialog() ;
			break ;
		case 1 :
			Quit() ;
			break ;
		default :
			return(E_APP_NONE) ;
	}
	return(E_APP_NONE) ;
}

LOCAL_C VOID DoStatus(VOID) {
	TEXT				buf[128] ;

	p_atos(	buf, "%s : %+03u-%+03u %+03u",
				file.name,
				pdata->fontinfo.low_ch,
				pdata->fontinfo.high_ch,
				pdata->fontinfo.low_ch + (pdata->curr_line + pdata->curr_y) * pdata->chars_per_line + pdata->curr_x ) ;
	UpdateStatus(buf) ;
}

LOCAL_C INT FontUpdate(VOID) {

	if ( pdata->redraw ) {
		SCROLL_BAR_STATE		bary ;
		INT						iLp ;
		INT						jLp ;
		INT						ch ;

		for ( jLp = 0 ; jLp < MIN(pdata->disp_lines, pdata->num_lines) ; jLp++ ) {
			for ( iLp = 0 ; iLp < pdata->chars_per_line ; iLp++ ) {
				ch = pdata->fontinfo.low_ch + (pdata->curr_line + jLp) * pdata->chars_per_line + iLp ;
				DrawChar(ch, iLp, jLp) ;
			}
		}

		InvertChar(pdata->curr_x, pdata->curr_y) ;

		DoStatus() ;

		bary.start = (ULONG) pdata->curr_line ;
		bary.size = (ULONG) pdata->disp_lines ;
		bary.total = (ULONG) pdata->num_lines ;
		UpdateYScroll(&bary) ;

		pdata->redraw = FALSE ;
	}

	return(E_APP_NONE) ;
}

LOCAL_C INT FontPlainKey(WMSG_KEY *pkey) {
	BOOL			ud_status = FALSE ;

	switch (pkey->keycode) {
		case W_KEY_PAGE_DOWN :
			/* Move individual cursor - PAGE DOWN - moving the page
				if necessary */
			if ( pkey->modifiers & W_SHIFT_MODIFIER ) {
				/* Move whole page one page down */
				pdata->curr_line = MIN(pdata->curr_line + pdata->disp_lines, pdata->last_top_line) ;
				pdata->redraw = TRUE ;
			}
			else if ( pdata->curr_y < pdata->disp_lines - 1 ) {
				/* Just move down 1 */
				InvertChar(pdata->curr_x, pdata->curr_y) ;
				InvertChar(pdata->curr_x, pdata->curr_y = pdata->disp_lines - 1) ;
				ud_status = TRUE ;
			}
			else if (	pdata->curr_y == pdata->disp_lines - 1 &&
							pdata->curr_line < pdata->last_top_line ) {
				/* Move whole page one line down */
				pdata->curr_line = MIN(pdata->curr_line + pdata->disp_lines, pdata->last_top_line) ;
				pdata->redraw = TRUE ;
			}
			break ;

		case W_KEY_PAGE_UP :
			/* Move individual cursor - PAGE UP - moving the whole page
				if necessary */
			if ( pkey->modifiers & W_SHIFT_MODIFIER ) {
				/* Move whole page one page up */
				pdata->curr_line -= (	pdata->curr_line >= pdata->disp_lines ?
													pdata->disp_lines :
													pdata->curr_line ) ;
				pdata->redraw = TRUE ;
			}
			else if ( pdata->curr_y > 0 ) {
				InvertChar(pdata->curr_x, pdata->curr_y) ;
				InvertChar(pdata->curr_x, pdata->curr_y = 0) ;
				ud_status = TRUE ;
			}
			else if (	pdata->curr_y == 0 &&
							pdata->curr_line > 0 ) {
				pdata->redraw = TRUE ;
				pdata->curr_line -= (	pdata->curr_line >= pdata->disp_lines ?
													pdata->disp_lines :
													pdata->curr_line ) ;
			}
			break ;

		case W_KEY_DOWN :
			if ( pkey->modifiers & W_SHIFT_MODIFIER ) {
				if ( pdata->curr_line < pdata->last_top_line ) {
					pdata->redraw = TRUE ;
					if ( pkey->modifiers & W_CTRL_MODIFIER ) {
						/* Bottom */
						pdata->curr_line = pdata->last_top_line ;
					}
					else {
						pdata->curr_line++ ;
					}
				}
			}
			else {
				/* Move individual cursor one line down - moving the page
					if necessary */
				if ( pdata->curr_y < pdata->disp_lines - 1 ) {
					InvertChar(pdata->curr_x, pdata->curr_y) ;
					InvertChar(pdata->curr_x, ++pdata->curr_y) ;
					ud_status = TRUE ;
				}
				else if (	pdata->curr_y == pdata->disp_lines - 1 &&
								pdata->curr_line < pdata->last_top_line ) {
					pdata->curr_line++ ;
					pdata->redraw = TRUE ;
				}
			}
			break ;

		case W_KEY_UP :
			if ( pkey->modifiers & W_SHIFT_MODIFIER ) {
				if ( pdata->curr_line > 0 ) {
					pdata->redraw = TRUE ;
					if ( pkey->modifiers & W_CTRL_MODIFIER ) {
						/* Move whole page one line up (or top) */
						pdata->curr_line = 0 ;
					}
					else {
						pdata->curr_line-- ;
					}
				}
			}
			else {
				/* Move individual cursor one line up - moving the page up
					if necessary */
				if ( pdata->curr_y > 0 ) {
					InvertChar(pdata->curr_x, pdata->curr_y) ;
					InvertChar(pdata->curr_x, --pdata->curr_y) ;
					ud_status = TRUE ;
				}
				else if (	pdata->curr_y == 0 &&
								pdata->curr_line > 0 ) {
					pdata->curr_line-- ;
					pdata->redraw = TRUE ;
				}
			}
			break ;

		case W_KEY_HOME :
			/* Move individual cursor - HOME */
			if ( pdata->curr_x > 0 ) {
				InvertChar(pdata->curr_x, pdata->curr_y) ;
				InvertChar(pdata->curr_x = 0, pdata->curr_y) ;
				ud_status = TRUE ;
			}
			break ;

		case W_KEY_LEFT :
			/* Move individual cursor - LEFT */
			if ( pdata->curr_x > 0 ) {
				InvertChar(pdata->curr_x, pdata->curr_y) ;
				InvertChar(--pdata->curr_x, pdata->curr_y) ;
				ud_status = TRUE ;
			}
			break ;

		case W_KEY_END :
			/* Move individual cursor - END */
			if ( pdata->curr_x < pdata->chars_per_line - 1 ) {
				InvertChar(pdata->curr_x, pdata->curr_y) ;
				InvertChar(pdata->curr_x = pdata->chars_per_line - 1, pdata->curr_y) ;
				ud_status = TRUE ;
			}
			break ;

		case W_KEY_RIGHT :
			/* Move individual cursor - RIGHT */
			if ( pdata->curr_x < pdata->chars_per_line - 1 ) {
				InvertChar(pdata->curr_x, pdata->curr_y) ;
				InvertChar(++pdata->curr_x, pdata->curr_y) ;
				ud_status = TRUE ;
			}
			break ;

		default :
			break ;
	}

	if ( ud_status || pdata->redraw )
		DoStatus() ;

	return(E_APP_NONE) ;
}

#pragma restore

LOCAL_C INT FontRecog(BYTE *buf, UINT buflen) {
	P_FSIG		norm_sig = {"FON", 'F'+'O'+'N', 0x30, 0x30} ;
	P_FSIG		fast_sig = {"FN1", 'F'+'N'+'1', 0x10, 0x10} ;

	buflen = MIN(buflen, sizeof(P_FSIG)) ;
	return(	!p_bcmp(buf, buflen, &norm_sig, buflen) ||
				!p_bcmp(buf, buflen, &fast_sig, buflen) ) ;
}

GLDEF_C VOID FontDefns(DEFNS *pdefns) {
	pdefns->pfRecognize =	FontRecog ;

	pdefns->pcmds =			Fontcmds ;
	pdefns->pmdata =			Fontmdata ;
	pdefns->nHelp =			RH_FONT ;
	pdefns->flags =			SCROLL_Y | STATUS_BAR ;
	pdefns->style =			G_STY_MONO ;

	pdefns->pfCleanUp =		FontCleanUp ;
	pdefns->pfInit =			FontInit ;
	pdefns->pfFileInfo =		FontFileInfo ;
	pdefns->pfUpdate =		FontUpdate ;
	pdefns->pfMenuExec =		FontMenuExec ;
	pdefns->pfPlainKey =		FontPlainKey ;
}

